﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework;

namespace Obsidian.Input
{
    /// <summary>
    /// Provides a simple binding table to bind buttons, keys, and axis to names.
    /// </summary>
    public class InputManager
    {
        internal static Dictionary<string, List<InputAxesMap>> axesMap;

        private KeyboardState previousKeyboardState;
        private KeyboardState currentKeyboardState;

        private MouseState previousMouseState;
        private MouseState currentMouseState;

        private GamePadState previousGamePadState;
        private GamePadState currentGamePadState;

        public InputManager()
        {
            axesMap = new Dictionary<string, List<InputAxesMap>>();

            // setup standard axes
            var horizontalAxesList = new List<InputAxesMap>()
            {
                new InputAxesMap()
                {
                    Name = "Horizontal",
                    NegativeButton = ObsidianButton.Left,
                    PositiveButton = ObsidianButton.Right,
                    Gravity = 3,
                    Dead = 0.001f,
                    Sensitivity = 3,
                    Type = InputType.KeyOrMouseButton,
                }
            };
            axesMap.Add("Horizontal", horizontalAxesList);

            var verticalAxesList = new List<InputAxesMap>()
            {
                new InputAxesMap()
                {
                    Name = "Vertical",
                    NegativeButton = ObsidianButton.Down,
                    PositiveButton = ObsidianButton.Up,
                    Gravity = 3,
                    Dead = 0.001f,
                    Sensitivity = 3,
                    Type = InputType.KeyOrMouseButton,
                }
            };
            axesMap.Add("Vertical", verticalAxesList);
        }

        public void Update()
        {
            // update mouse
            previousMouseState = currentMouseState;
            currentMouseState = Mouse.GetState();

            // update keys
            previousKeyboardState = currentKeyboardState;
            currentKeyboardState = Keyboard.GetState();
            
            // update joystick
            // TODO !!!

            // update Input
            // AnyKey
            if (currentKeyboardState.GetPressedKeys().Length > 0 || currentMouseState.LeftButton == ButtonState.Pressed ||
                currentMouseState.RightButton == ButtonState.Pressed || currentMouseState.MiddleButton == ButtonState.Pressed)
                OldInput.AnyKey = true;
            else
                OldInput.AnyKey = false;

            // AnyKeyDown
            if ((previousKeyboardState.GetPressedKeys().Length == 0 && previousKeyboardState.GetPressedKeys().Length > 0)
                || (previousMouseState.LeftButton == ButtonState.Released && currentMouseState.LeftButton == ButtonState.Pressed)
                || (previousMouseState.RightButton == ButtonState.Released && currentMouseState.RightButton == ButtonState.Pressed)
                || (previousMouseState.MiddleButton == ButtonState.Released && currentMouseState.MiddleButton == ButtonState.Pressed))
                OldInput.AnyKeyDown = true;
            else
                OldInput.AnyKeyDown = false;

            // MousePosition
            OldInput.MousePosition = new Vector2(Mouse.GetState().X, Mouse.GetState().Y);

            // here we need to update the axes map with any changes and then update the Input class to match.
            foreach (var axesList in axesMap.Values)
            {
                foreach (var axes in axesList)
                {
                    switch (axes.Type)
                    {
                        case InputType.KeyOrMouseButton:
                            axes.Update(previousKeyboardState, currentKeyboardState);
                            break;
                        case InputType.MouseMovement:
                            axes.Update(previousMouseState, currentMouseState);
                            break;
                        case InputType.JoystickAxes:
                            // TODO - need a joystick!!!
                            break;
                    }
                }
            }
        }
    }
}
